package cn.zebra.dev.member.module.login.service;

import cn.zebra.dev.base.module.member.constant.MemberStatusConstant;
import cn.zebra.dev.base.module.member.entity.BaseMember;
import cn.zebra.dev.base.module.member.service.BaseMemberService;
import cn.zebra.dev.common.constant.SysConstant;
import cn.zebra.dev.common.utils.SecurityUtils;
import cn.zebra.dev.jwt.utils.JwtTokenUtil;
import cn.zebra.dev.member.module.security.entity.MemberDetailsEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * @author runnable@sina.cn
 */
@Service
public class LoginService {

    @Autowired
    private BaseMemberService memberService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * App登录 成功返回token
     *
     * @param account   手机号
     * @param password  登录密码
     * @param loginType 登录类型 (0手机号 1 用户名登录)
     * @return token
     */
    public String login(String account, String password, Integer loginType) {
        BaseMember member;
        if (loginType == 0) {
            member = memberService.findMemberByPhone(account);
        } else if (loginType == 1) {
            member = memberService.findByMemberName(account);
        } else {
            throw new RuntimeException("不支持的登录类型!");
        }
        if (member == null) {
            throw new RuntimeException("用户名或密码不正确!");
        }
        if (member.getStatus().equals(MemberStatusConstant.FROZEN)) {
            throw new RuntimeException("您的账号已被冻结!");
        }
        if (!SecurityUtils.getMd5(member.getSalt() + password).equals(member.getPassword())) {
            throw new RuntimeException("用户名或密码不正确!");
        }
        MemberDetailsEntity userDetails = new MemberDetailsEntity(member);
        userDetails.setLoginName(account);
        return initToken(account, userDetails);
    }

    /**
     * 退出登录
     */
    @Async
    public void logout(String account) {
        RedisOperations<String, String> operations = redisTemplate.opsForValue().getOperations();
        operations.delete(SysConstant.USER_TOKEN + account);
        operations.delete(SysConstant.MEMBER + account);
        SecurityContextHolder.clearContext();
    }

    /**
     * 手机号登录并返回token
     *
     * @param phone 手机号
     * @return token
     */
    public String phoneLogin(String phone) {
        BaseMember member = memberService.findMemberByPhone(phone);
        if (member == null) {
            throw new RuntimeException("用户不存在");
        }
        MemberDetailsEntity userDetails = new MemberDetailsEntity(member);
        return initToken(phone, userDetails);
    }

    /**
     * 根据用户名和用户信息初始化token
     *
     * @param userName    用户名
     * @param userDetails 用户信息
     * @return token
     */
    private String initToken(String userName, MemberDetailsEntity userDetails) {
        String token = JwtTokenUtil.validateTokenExist(userName, userDetails, redisTemplate.opsForValue());
        setTokenAndUserDetails(userName, userDetails, token);
        return token;
    }

    /**
     * 设置用户token存放redis和注入Security用户信息
     *
     * @param userName    用户名
     * @param userDetails 用户详情
     * @param token       token
     */
    @Async
    void setTokenAndUserDetails(String userName, MemberDetailsEntity userDetails, String token) {
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //缓存token
        redisTemplate.opsForValue().set(SysConstant.USER_TOKEN + userName, token, 7, TimeUnit.DAYS);
    }
}
